﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using EditableBusinessObjects.Postsharp.Public;
using EntityFrameworkContrib.PostSharp4EF;
using System.Runtime.Serialization;
using CyclicReferences.Public;
using System.Collections.ObjectModel;

namespace EFContrib.PS4EF.Tst.RelationShipType
{
    /// <summary>
    /// Summary description for AttachDetachTest
    /// </summary>
    [TestClass]
    public class AttachDetachTest
    {
        #region setup
        public AttachDetachTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion 
        #endregion

        void ClearDatabase()
        {
            using (SimpleRelationshipTestEntities context = new SimpleRelationshipTestEntities())
            {
                foreach (Customer old in context.Customer)
                {
                    context.DeleteObject(old);
                }
                context.SaveChanges();
            }
        }

        [TestMethod]
        public void testAttachDetachWithRelationsBreadth()
        {

            ClearDatabase();


            Customer c = new Customer { Name = "Ruurd Boeke" };
            Car car1 = new Car { Make = "Porsche", Customer = c };
            Car car2 = new Car { Make = "Ferrari", Customer = c };
            Car car3 = new Car { Make = "BMW" };    // not connected yet
            Order order1 = new Order { Amount = 10, Customer = c };


            IEditableBusinessObject eC = c as IEditableBusinessObject;
            string MsgOnWire = "";

            // at this point, we are not at all attached
            using (SimpleRelationshipTestEntities context = new SimpleRelationshipTestEntities())
            {
                context.AddToCustomer(c);
                context.SaveChanges();  // this instructs context to start changetracking

                c.Name = "Changed"; // change name
                car1.Make = "Porsche renamed"; // change in another object in the graph
                c.Cars.Add(car3);   // add another object to the list
                c.Cars.Remove(car1); // remove a car from the list

                // now we need to create a version of the object that can be serialized well
                // this will call the context to get the 'original' values and save them to the loaded state (using IEditableBusinessObject)
                ((IContextAware)c).CreateSerializableState(context);

                DataContractSerializer s = new DataContractSerializer(c.GetType(), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());

                MsgOnWire = s.GetWellFormedToContract(c);
            }


            // imagine we are the client getting a message and deserializing it
            DataContractSerializer s2 = new DataContractSerializer(typeof(CustomerClient), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
            CustomerClient c2 = (CustomerClient)s2.UnwrapFromString(MsgOnWire);

            c2.Orders.First().Amount = 20;
            OrderClient order2 = new OrderClient { Amount = 30, Customer = c2 };
            c2.Cars.Add(new CarClient { Make = "Chrysler", Customer = c2 });
            
            // we have edited everything, let's get back to the server
            DataContractSerializer s3 = new DataContractSerializer(typeof(CustomerClient), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
            MsgOnWire = s3.GetWellFormedToContract(c2);




            // we're at the server
            using (SimpleRelationshipTestEntities context = new SimpleRelationshipTestEntities())
            {
                DataContractSerializer s4 = new DataContractSerializer(typeof(Customer), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
                Customer c3 = (Customer)s4.UnwrapFromString(MsgOnWire);

                ((IContextAware)c3).AttachGraphToContext(context,
                    delegate(object source)
                    {
                        return source.GetType().Name;   // our setnames correspond to our classname. 
                    });


                context.SaveChanges();
            }




        }

        [TestMethod]
        public void testAttachDetachWithRelationsSimple()
        {

            ClearDatabase();


            Customer c = new Customer { Name = "Ruurd Boeke" };
            Car car1 = new Car { Make = "Saab", Customer = c };
            Order order1 = new Order { Amount = 2, Customer = c };


            IEditableBusinessObject eC = c as IEditableBusinessObject;
            string MsgOnWire = "";

            // at this point, we are not at all attached
            using (SimpleRelationshipTestEntities context = new SimpleRelationshipTestEntities())
            {
                context.AddToCustomer(c);
                context.SaveChanges();  // this instructs context to start changetracking

                ((IContextAware)c).CreateSerializableState(context);

                DataContractSerializer s = new DataContractSerializer(c.GetType(), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());

                MsgOnWire = s.GetWellFormedToContract(c);
            }


            // imagine we are the client getting a message and deserializing it
            DataContractSerializer s2 = new DataContractSerializer(typeof(CustomerClient), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
            CustomerClient c2 = (CustomerClient)s2.UnwrapFromString(MsgOnWire);

            // delete
            c2.Cars.First().Customer = null;
            c2.Cars.Clear();

            // add
            OrderClient order2 = new OrderClient { Amount = 100, Customer = c2 };
            c2.Orders.Add(order2);

            // change
            c2.Name = "Changed";

            // we have edited everything, let's get back to the server
            DataContractSerializer s3 = new DataContractSerializer(typeof(CustomerClient), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
            MsgOnWire = s3.GetWellFormedToContract(c2);

            // we're at the server
            using (SimpleRelationshipTestEntities context = new SimpleRelationshipTestEntities())
            {
                DataContractSerializer s4 = new DataContractSerializer(typeof(Customer), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
                Customer c3 = (Customer)s4.UnwrapFromString(MsgOnWire);

                ((IContextAware)c3).AttachGraphToContext(context,
                    delegate(object source)
                    {
                        return source.GetType().Name;   // our setnames correspond to our classname. 
                    });


                context.SaveChanges();
            }




        }

    }
}
